package com.cml.domain.service;

import com.alibaba.fastjson.JSONObject;
import com.cml.common.constant.MessageType;
import com.cml.common.constant.NodeStatus;
import com.cml.common.context.ServerContext;
import com.cml.common.dto.entity.Message;
import com.cml.common.dto.entity.ServiceInstance;
import com.cml.common.dto.entity.SoltMetadata;
import com.cml.common.dto.message.*;
import com.cml.domain.entity.DefaultMessage;
import com.cml.domain.entity.Session;
import com.cml.domain.entity.Solt;
import com.cml.infrastructure.ClientNetworkManager;
import com.cml.infrastructure.ClientQueueManage;
import com.cml.infrastructure.MessageQueueManager;
import com.cml.infrastructure.NetworkManager;
import org.apache.log4j.Logger;

import java.util.List;
import java.util.Map;

/**
 * 姓名：陈茂林
 * 时间：2023/10/16 14:13
 * 描述：
 */
public class ClientManagerService {
    private SoltContextManagerService soltContextManagerService;

    private ClientNetworkManager clientNetworkManager ;

    private NetworkManager serverNetworkManager;
    private ServerContext serverContext;

    Logger logger = Logger.getLogger(ClientManagerService.class);

    public ClientManagerService(ServerContext serverContext){
        this.soltContextManagerService =serverContext.getSoltManagerService();
        this.serverNetworkManager = serverContext.getNetworkManager();
    }
    public void start(){
        this.clientNetworkManager = new ClientNetworkManager(this);
        this.clientNetworkManager.start();
        //启动实例的副本同步
        ServiceInstanceReplicasManagerService serviceInstanceReplicasManagerService = new ServiceInstanceReplicasManagerService(serverContext);
        serviceInstanceReplicasManagerService.replicasSynStart();
    }

    public Message process(Session session, Message message){
        if(message instanceof FetchSlotsAllocationRequst){
            return fetchSlotsAllocation();
        }else if(message instanceof FetchAllServerListRequest){
            return fetchAllServerList();
        } else if (message instanceof  ServiceRegisterRequest) {
            if (message.getMessageType() == MessageType.CLIENT_REQUEST_SERVICE_REGISTER_MESSAGE) {
                return registerServiceInstance((ServiceRegisterRequest) message);
            } else {
                if (message instanceof ServiceHearbeatRequest) {
                    heartbeat((ServiceHearbeatRequest) message);
                }
            }
        }else if(message instanceof  ServiceSubscribeRequest){
            subscribe(session, (ServiceSubscribeRequest) message);
        }
        return null;
    }

    private void subscribe(Session session,ServiceSubscribeRequest serviceSubscribeRequest){
        logger.info("sessionId:"+session.getSessionId()+"订阅服务："+serviceSubscribeRequest.getServiceName());
        Solt solt = soltContextManagerService.getServiceNameSolt(serviceSubscribeRequest.getServiceName());
        solt.subscribe(session,serviceSubscribeRequest.getServiceName());
    }

    private void heartbeat(ServiceHearbeatRequest serviceHearbeatRequest){
        logger.info("收到"+serviceHearbeatRequest.getIp()+":"+serviceHearbeatRequest.getPort()+"心跳消息");
        ServiceInstance serviceInstance = new ServiceInstance.Builder()
                .setServiceRegisterRequest(serviceHearbeatRequest)
                .build();
        Solt solt=soltContextManagerService.getServiceNameSolt(serviceHearbeatRequest.getServiceName());
        solt.hearbeat(serviceInstance);
        if(solt.getReplicasServerNodeId() != null){
            try {
                DefaultMessage message = new DefaultMessage();
                message.setDefaultMessageType(MessageType.CLIENT_REQUEST_SERVICE_HEARBEAT_MESSAGE);
                String messageJson = JSONObject.toJSONString(serviceHearbeatRequest);
                message.setDefaultMessage(messageJson.getBytes());
                MessageQueueManager.sendMessage(solt.getReplicasServerNodeId(), message);
            }catch (Exception e){
                logger.error(e.getMessage(),e);
            }
        }
    }

    private Message registerServiceInstance(ServiceRegisterRequest serviceRegisterRequest){
        ServiceInstance serviceInstance = new ServiceInstance.Builder()
                .setServiceRegisterRequest(serviceRegisterRequest)
                .build();
        Solt solt=soltContextManagerService.getServiceNameSolt(serviceInstance.getServiceName());
        solt.registerServiceInstance(serviceInstance);
        if(solt.getReplicasServerNodeId() != null){
            try {
                DefaultMessage message = new DefaultMessage();
                message.setDefaultMessageType(MessageType.CLIENT_REPONSE_SERVICE_REGISTER_MESSAGE);
                String messageJson = JSONObject.toJSONString(serviceRegisterRequest);
                message.setDefaultMessage(messageJson.getBytes());
                MessageQueueManager.sendMessage(solt.getReplicasServerNodeId(), message);
            }catch (Exception e){
                logger.error(e.getMessage(),e);
            }
        }
        return new ServiceRegisterResponse();
    }

    private FetchAllServerListReponse fetchAllServerList(){
        FetchAllServerListReponse fetchAllServerListReponse = new FetchAllServerListReponse();
        Map allRemoteServerNode =this.serverNetworkManager.getAllRemoteServerNode();
        fetchAllServerListReponse.setAllServerList(JSONObject.toJSONString(allRemoteServerNode));
        return  fetchAllServerListReponse;
    }

    private FetchSlotsAllocationResponse fetchSlotsAllocation(){
        //等待故障恢复完成
        while ( NodeStatus.getInstance().getCurStatus().equals(NodeStatus.NODE_HA)){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                logger.error(e);
            }
        }
        List<SoltMetadata> soltMetadataList= this.soltContextManagerService.getSlotsAllocation();
        FetchSlotsAllocationResponse fetchSlotsAllocationResponse = new FetchSlotsAllocationResponse();
        fetchSlotsAllocationResponse.setSoltMetadataList(JSONObject.toJSONString(soltMetadataList));
        return fetchSlotsAllocationResponse;
    }
}
